import pygame


from settings import *
from support import import_folder
from timer import Timer
from effect import DashEffect, LevelUpEffect


class Player(pygame.sprite.Sprite):


    def __init__(self,pos,group,collision_sprites,monster_sprites):
        super().__init__(group)

        self.import_assets()
        self.status='down_idle'
        self.frame_index=0

        self.display_surf=pygame.display.get_surface()

        self.max_health = 7
        self.health = self.max_health
        self.max_mp = 4  # 最大MP值
        self.mp = self.max_mp  # 当前MP值
        self.score = 0  # 添加分数属性
        
        # 等级系统
        self.level = 1
        self.max_level = 10
        self.exp = 0
        self.exp_to_next_level = 10  # 初始升级所需经验值
        
        self.show_death_menu = False  # 添加死亡菜单标志
        
        # 添加攻击显示相关的属性
        self.attack_points = []
        self.attack_display_time = 0
        self.attack_duration = 350  # 攻击动画持续时间（毫秒）

        #setup

        self.image = self.animations[self.status][self.frame_index]

        self.rect = self.image.get_rect(center=pos)

        #碰撞盒子

        self.z=LAYERS['main']
        #移动
        self.direction=pygame.math.Vector2()
        self.pos=pygame.math.Vector2(self.rect.center)
        self.speed=200
        #碰撞
        self.hitbox = self.rect.copy().inflate((-130, -85))
        self.hitbox.centery += self.rect.height // 4
        self.collision_sprites=collision_sprites

        self.monster_sprites = monster_sprites
        #计算器
        self.timer={
            'tool use':Timer(350,self.use_tool),
            'tool switch':Timer(200),
           
            'dash_invisible': Timer(1000, self.end_dash),  # 1秒的闪现持续时间
            'invincible': Timer(1000),  # 1秒无敌时间
            'mp_regen': Timer(6000, self.regen_mp)  # 6秒回复一点MP
        }
        #武器
        self.tools=['hoe','axe']
        self.tool_index=0
        self.selected_tool=self.tools[self.tool_index]

        #背包


        # 添加闪现相关的属性
        self.can_dash = True
        self.dash_cooldown = 3000
        self.last_dash_time = 0
        self.is_dashing = False

        self.is_invincible = False  # 是否处于无敌状态

        # MP消耗冷却
        self.mp_cooldown = 500  # 500毫秒
        self.last_mp_use = 0

        

    def use_tool(self):
        print('tool use')
        if self.selected_tool == 'hoe':
            # 播放锄头音效
            if hasattr(self, 'level_instance') and hasattr(self.level_instance, 'game'):
                self.level_instance.game.play_sound('hoe')
                
            # 设置攻击范围
            attack_range = 150  # 攻击范围（的高）
            bottom_width_multiplier = 1.5  # 底边是上底的倍数
            direction = self.status.split('_')[0]
            
            # 获取hitbox的尺寸
            hitbox_width = self.hitbox.width
            hitbox_height = self.hitbox.height
            
            # 获取碰撞体积的中心点
            center_x = self.hitbox.centerx
            center_y = self.hitbox.centery
            
            # 根据方向计算梯形的四个顶点
            if direction == 'left':
                top_left = (center_x, center_y - hitbox_height/2)
                top_right = (center_x, center_y + hitbox_height/2)
                bottom_left = (center_x - attack_range, center_y - (hitbox_height/2 * bottom_width_multiplier))
                bottom_right = (center_x - attack_range, center_y + (hitbox_height/2 * bottom_width_multiplier))
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'right':
                top_left = (center_x, center_y - hitbox_height/2)
                top_right = (center_x, center_y + hitbox_height/2)
                bottom_left = (center_x + attack_range, center_y - (hitbox_height/2 * bottom_width_multiplier))
                bottom_right = (center_x + attack_range, center_y + (hitbox_height/2 * bottom_width_multiplier))
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'up':
                top_left = (center_x - hitbox_width/2, center_y)
                top_right = (center_x + hitbox_width/2, center_y)
                bottom_left = (center_x - (hitbox_width/2 * bottom_width_multiplier), center_y - attack_range)
                bottom_right = (center_x + (hitbox_width/2 * bottom_width_multiplier), center_y - attack_range)
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'down':
                top_left = (center_x - hitbox_width/2, center_y)
                top_right = (center_x + hitbox_width/2, center_y)
                bottom_left = (center_x - (hitbox_width/2 * bottom_width_multiplier), center_y + attack_range)
                bottom_right = (center_x + (hitbox_width/2 * bottom_width_multiplier), center_y + attack_range)
                points = [top_left, top_right, bottom_right, bottom_left]
            
            # 将梯形的点信息保存，用于在 CameraGroup 中绘制
            self.attack_points = points
            
            # 攻击怪物
            attack_damage = 5  # 使用锄头时的攻击伤害
            
            # 检查攻击范围内的怪物
            for sprite in self.monster_sprites.sprites():
                if hasattr(sprite, 'hitbox'):
                    if self.point_in_polygon(sprite.hitbox.center, points):
                        sprite.take_damage(attack_damage)
            
            # 设置一个短的计时器来清除攻击范围显示
            self.attack_display_time = pygame.time.get_ticks()
        
        if self.selected_tool == 'axe':
            # 播放斧头音效
            if hasattr(self, 'level_instance') and hasattr(self.level_instance, 'game'):
                self.level_instance.game.play_sound('axe')
                
            # 设置攻击范围
            attack_range = 65  # 攻击范围（的高）
            bottom_width_multiplier = 4  # 底边是上底的倍数
            direction = self.status.split('_')[0]
            
            # 获取hitbox的尺寸
            hitbox_width = self.hitbox.width
            hitbox_height = self.hitbox.height
            
            # 获取碰撞体积的中心点
            center_x = self.hitbox.centerx
            center_y = self.hitbox.centery
            
            # 根据方向计算梯形的四个顶点
            if direction == 'left':
                top_left = (center_x, center_y - hitbox_height/2)
                top_right = (center_x, center_y + hitbox_height/2)
                bottom_left = (center_x - attack_range, center_y - (hitbox_height/2 * bottom_width_multiplier))
                bottom_right = (center_x - attack_range, center_y + (hitbox_height/2 * bottom_width_multiplier))
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'right':
                top_left = (center_x, center_y - hitbox_height/2)
                top_right = (center_x, center_y + hitbox_height/2)
                bottom_left = (center_x + attack_range, center_y - (hitbox_height/2 * bottom_width_multiplier))
                bottom_right = (center_x + attack_range, center_y + (hitbox_height/2 * bottom_width_multiplier))
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'up':
                top_left = (center_x - hitbox_width/2, center_y)
                top_right = (center_x + hitbox_width/2, center_y)
                bottom_left = (center_x - (hitbox_width/2 * bottom_width_multiplier), center_y - attack_range)
                bottom_right = (center_x + (hitbox_width/2 * bottom_width_multiplier), center_y - attack_range)
                points = [top_left, top_right, bottom_right, bottom_left]
                
            elif direction == 'down':
                top_left = (center_x - hitbox_width/2, center_y)
                top_right = (center_x + hitbox_width/2, center_y)
                bottom_left = (center_x - (hitbox_width/2 * bottom_width_multiplier), center_y + attack_range)
                bottom_right = (center_x + (hitbox_width/2 * bottom_width_multiplier), center_y + attack_range)
                points = [top_left, top_right, bottom_right, bottom_left]
            
            # 将梯形的点信息保存，用于在 CameraGroup 中绘制
            self.attack_points = points
            
            # 攻击怪物
            attack_damage = 7  # 使用斧头时的攻击伤害
            
            # 检查攻击范围内的怪物
            for sprite in self.monster_sprites.sprites():
                if hasattr(sprite, 'hitbox'):
                    if self.point_in_polygon(sprite.hitbox.center, points):
                        sprite.take_damage(attack_damage)
            
            # 设置一个短的计时器来清除攻击范围显示
            self.attack_display_time = pygame.time.get_ticks()

    def point_in_polygon(self, point, polygon):
        """检查点是否在多边形内部（射线法）"""
        x, y = point
        n = len(polygon)
        inside = False
        
        j = n - 1
        for i in range(n):
            if ((polygon[i][1] > y) != (polygon[j][1] > y) and
                (x < (polygon[j][0] - polygon[i][0]) * (y - polygon[i][1]) /
                 (polygon[j][1] - polygon[i][1]) + polygon[i][0])):
                inside = not inside
            j = i
        
        return inside

    


   
    def import_assets(self):
        self.animations={'up':[],'down':[],'left':[],'right':[],
                         'right_idle': [],'left_idle':[],'up_idle':[],'down_idle':[],
                         'right_hoe': [],'left_hoe':[],'up_hoe':[],'down_hoe':[],
                         'right_axe': [],'left_axe':[],'up_axe':[],'down_axe':[],
                         'right_water': [],'left_water':[],'up_water':[],'down_water':[],
                         


        }
        for animation in self.animations.keys():
            full_path='./graphics/character/'+ animation
            self.animations[animation]=import_folder(full_path)
        print(self.animations)

    def animate(self,dt):
        self.frame_index+=4*dt
        if self.frame_index>=len(self.animations[self.status]):
            self.frame_index=0

        self.image = self.animations[self.status][int(self.frame_index)]



    def input(self):
        keys = pygame.key.get_pressed()
        current_time = pygame.time.get_ticks()
    
        # 添加闪现功能
        if keys[pygame.K_1] and self.mp > 0 and self.can_dash:  # 添加can_dash的检查
            # 检查MP消耗冷却
            if current_time - self.last_mp_use >= self.mp_cooldown:
                self.dash()
                self.mp -= 1
                self.last_mp_use = current_time
                return  # 执行闪现后直接返回，避免其他移动输入
        elif keys[pygame.K_1] and not self.can_dash:  # 如果在冷却中按1，显示提示
            remaining_cooldown = (self.last_dash_time + self.dash_cooldown - current_time) / 1000
            print(f"闪现冷却中: 还需等待 {remaining_cooldown:.1f} 秒")
        
        if not self.timer['tool use'].active:
            if keys[pygame.K_UP]:
                self.direction.y = -1
                self.status = 'up'
            elif keys[pygame.K_DOWN]:
                self.direction.y = +1
                self.status = 'down'
            else:
                self.direction.y = 0

            if keys[pygame.K_LEFT]:
                self.direction.x = -1
                self.status = 'left'
            elif keys[pygame.K_RIGHT]:
                self.direction.x = 1
                self.status = 'right'
            else:
                self.direction.x = 0

            if keys[pygame.K_SPACE]:
                # 激活计算器和具
                self.timer['tool use'].activate()
                self.direction = pygame.math.Vector2()
                self.frame_index = 0

            if keys[pygame.K_q] and not self.timer['tool switch'].active:
                self.timer['tool switch'].activate()
                self.tool_index += 1
                if self.tool_index >= len(self.tools):
                    self.tool_index = 0
                self.selected_tool = self.tools[self.tool_index]


    def get_status(self):
        #移动状态转换

        if self.direction.magnitude() == 0:
            self.status = self.status.split('_')[0]+'_idle'

        #���器
        if self.timer['tool use'].active:
           self.status=self.status.split('_')[0]+'_'+self.selected_tool



    def update_timer(self):
        for timer in self.timer.values():
            timer.update()

    def move(self, dt):
        # 保存移动前的位置
        previous_x = self.pos.x
        previous_y = self.pos.y

        if self.direction.magnitude() > 0:
            self.direction = self.direction.normalize()

        # 水平移
        self.pos.x += self.direction.x * self.speed * dt
        self.hitbox.centerx = round(self.pos.x)
        self.rect.centerx = self.hitbox.centerx
        
        # 检查水平碰撞并处理
        if self.check_collisions('horizontal'):
            self.pos.x = previous_x
            self.hitbox.centerx = round(self.pos.x)
            self.rect.centerx = self.hitbox.centerx

        # 垂直移动
        self.pos.y += self.direction.y * self.speed * dt
        # 更新hitbox位置，保持在玩家的下半身，并向上偏5像素
        self.hitbox.centery = round(self.pos.y) + self.rect.height // 4 - 10
        self.rect.centery = round(self.pos.y)
        
        # 检查垂直碰撞并处理
        if self.check_collisions('vertical'):
            self.pos.y = previous_y
            self.hitbox.centery = round(self.pos.y) + self.rect.height // 4 - 10
            self.rect.centery = self.hitbox.centery

    def check_collisions(self, direction):
        # 检查与固定障碍物的碰撞
        for sprite in self.collision_sprites.sprites():
            if hasattr(sprite, 'hitbox'):
                if sprite.hitbox.colliderect(self.hitbox):
                    return True

        # 检查与怪物的碰撞
        for monster in self.monster_sprites.sprites():
            if monster.hitbox.colliderect(self.hitbox):
                print(f"玩家与怪物碰撞: 方向={direction}, 玩家位置={self.pos}, 怪物位置={monster.pos}")
                # 处理碰撞，玩家停止移动
                if direction == 'horizontal':
                    if self.direction.x > 0:  # 向右移动
                        self.pos.x -= self.direction.x * self.speed
                    elif self.direction.x < 0:  # 向左移动
                        self.pos.x -= self.direction.x * self.speed
                    self.hitbox.centerx = round(self.pos.x)
                    self.rect.centerx = self.hitbox.centerx
                elif direction == 'vertical':
                    if self.direction.y > 0:  # 向下移动
                        self.pos.y -= self.direction.y * self.speed
                    elif self.direction.y < 0:  # 向上移动
                        self.pos.y -= self.direction.y * self.speed
                    self.hitbox.centery = round(self.pos.y) + self.rect.height // 4 - 5
                    self.rect.centery = self.hitbox.centery
                return True

        return False

    def update(self, dt):
        current_time = pygame.time.get_ticks()
        
        # 检查闪现冷却
        if not self.can_dash and current_time - self.last_dash_time >= self.dash_cooldown:
            self.can_dash = True
        
        # 检查并处理MP回复
        if self.mp < self.max_mp:
            if not self.timer['mp_regen'].active:
                self.timer['mp_regen'].activate()
        
        self.input()
        self.get_status()
        self.update_timer()
        self.move(dt)
        
        # 只在非闪现状态下更新动画
        if not self.is_dashing:
            self.animate(dt)
        else:
            self.image = pygame.Surface((0, 0), pygame.SRCALPHA)  # 闪现时隐藏玩家
        
        # 更新无敌状态
        if self.is_invincible and not self.timer['invincible'].active:
            print("无敌状态结束")
            self.is_invincible = False
            
       
    
    def regen_mp(self):
        """每6秒回复一点MP的回调函数"""
        if self.mp < self.max_mp:
            self.mp = min(self.max_mp, self.mp + 1)
            #print(f"MP回复1点，当前MP: {self.mp}")
            # 如果MP还没满，继续激活计时器
            if self.mp < self.max_mp:
                self.timer['mp_regen'].activate()
    
    def dash(self):
        """冲刺功能"""
        current_time = pygame.time.get_ticks()
        
        if not self.can_dash:
            remaining_cooldown = (self.last_dash_time + self.dash_cooldown - current_time) / 1000
            print(f"闪现冷却中: 还需等待 {remaining_cooldown:.1f} 秒")
            return
        
        # 播放冲刺音效
        if hasattr(self, 'level_instance') and hasattr(self.level_instance, 'game'):
            self.level_instance.game.play_sound('dash')
        
        # 创建替身在原位置
        self.shadow = PlayerShadow(self.pos, self.hitbox, [self.groups()[0]])
        
        # 在原位置创建分身特效
        DashEffect(self.pos, [self.groups()[0]])
        
        dash_distance = 150
        direction = self.status.split('_')[0]
        
        # 保存原始位置
        original_pos = pygame.math.Vector2(self.pos)
        
        # 计算目标位置
        target_pos = pygame.math.Vector2(self.pos)
        if direction == 'up':
            target_pos.y -= dash_distance
        elif direction == 'down':
            target_pos.y += dash_distance
        elif direction == 'left':
            target_pos.x -= dash_distance
        elif direction == 'right':
            target_pos.x += dash_distance
        
        # 创建一个临时的hitbox来检查目标位置
        temp_hitbox = self.hitbox.copy()
        temp_hitbox.center = (round(target_pos.x), round(target_pos.y))
        
        # 检查目标位置是否在碰撞物体内
        collision_found = False
        for sprite in self.collision_sprites.sprites():
            if hasattr(sprite, 'hitbox'):
                if temp_hitbox.colliderect(sprite.hitbox):
                    collision_found = True
                    break
        
        if collision_found:
            # 如果目标位置有碰撞，寻找最近的可用位置
            step = 1  # 每次检查的步长
            for distance in range(dash_distance, 0, -step):
                test_pos = pygame.math.Vector2(original_pos)
                if direction == 'up':
                    test_pos.y -= distance
                elif direction == 'down':
                    test_pos.y += distance
                elif direction == 'left':
                    test_pos.x -= distance
                elif direction == 'right':
                    test_pos.x += distance
                
                temp_hitbox.center = (round(test_pos.x), round(test_pos.y))
                
                # 检查这个位置是否可用
                valid_position = True
                for sprite in self.collision_sprites.sprites():
                    if hasattr(sprite, 'hitbox'):
                        if temp_hitbox.colliderect(sprite.hitbox):
                            valid_position = False
                            break
                
                if valid_position:
                    # 找到可用位置，更新玩家位置
                    self.pos = test_pos
                    break
        else:
            # 如果目标位置没有碰撞，直接闪现
            self.pos = target_pos
        
        # 更新hitbox和rect位置
        self.hitbox.center = round(self.pos.x), round(self.pos.y)
        self.rect.center = self.hitbox.center
        
        # 更新状态
        self.is_dashing = True
        self.can_dash = False
        self.last_dash_time = current_time
        
        # 激活1秒的闪现计时器
        self.timer['dash_invisible'].activate()
        
        print(f"闪现到位置: {self.pos}")
    
    def end_dash(self):
        self.is_dashing = False
        if hasattr(self, 'shadow') and self.shadow:
            self.shadow.kill()
            self.shadow = None
    
    def take_damage(self, amount):
        if not self.is_invincible and not self.is_dashing:  # 在非无敌且非闪现状态下才能受伤
            self.health = max(0, min(self.max_health, self.health - amount))  # 限制生命值在0到max_health之间
            self.is_invincible = True
            self.timer['invincible'].activate()
            
            # 播放受伤音效
            if hasattr(self, 'level_instance') and hasattr(self.level_instance, 'game'):
                self.level_instance.game.play_sound('hurt')
                
            print(f"玩家受到 {amount} 点伤害，剩余生命值: {self.health}")
            if self.health == 0:
                print("玩家死亡")
    
    def add_score(self, amount):
        """增加分数"""
        self.score += amount
        print(f"获得 {amount} 分，Score: {self.score}")
    
    def add_exp(self, amount):
        """增加经验值并处理升级"""
        if self.level >= self.max_level:
            return

        self.exp += amount
        while self.exp >= self.exp_to_next_level and self.level < self.max_level:
            self.level_up()

    def level_up(self):
        """处理升级"""
        self.level += 1
        self.exp -= self.exp_to_next_level
        
        # 增加下一级所需经验值
        self.exp_to_next_level = int(self.exp_to_next_level * 1.5)
        
        # 升级奖励
        self.max_health = 7
        self.health = self.max_health  # 回满血
        self.max_mp = 4
        self.mp = self.max_mp  # 回满蓝
        
        # 创建升级特效
        LevelUpEffect(self.pos, [self.groups()[0]], self)
        
        # 播放升级音效
        if hasattr(self, 'level_instance') and hasattr(self.level_instance, 'game'):
            self.level_instance.game.play_sound('level_up')
            
  

      
    
class PlayerShadow(pygame.sprite.Sprite):
    def __init__(self, pos, player_hitbox, groups):
        super().__init__(groups)
        
        # 使用玩家实际的hitbox大小
        hitbox_size = (player_hitbox.width, player_hitbox.height)
        self.image = pygame.Surface(hitbox_size, pygame.SRCALPHA)
        self.rect = self.image.get_rect(center=pos)
        self.hitbox = self.rect.copy()
        self.z = LAYERS['main']
        
        # 绘制半透明灰色矩形
        pygame.draw.rect(self.image, (64, 64, 64, 64), ((0, 0), hitbox_size))
    
    def kill(self):
        super().kill()
    